﻿using NPoco;
using NPoco.Linq;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Beginner.Infrastructure.Helper;
using Beginner.Infrastructure;

namespace Beginner.Infrastructure.Data
{
    /// <summary>
    /// [资源库基类]继承它默认实现了IRepository接口
    /// </summary>
    /// <typeparam name="T">实体类型</typeparam>
    /// <typeparam name="TId">主键类型</typeparam>
    public class RepositoryBase<T, TId> where T : IAggregateRoot
    {
        #region 属性
        /// <summary>
        /// 数据库操作类 基于NPoco
        /// </summary>
        protected IDatabase DbBase { get { return DbHelper.Instance.CurrentContext; } }
        #endregion

        #region Query
        /// <summary>
        /// 根据主键ID获取实体
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns></returns>
        public virtual T GetById(TId id)
        {
            return DbBase.SingleOrDefaultById<T>(id);
        }
        /// <summary>
        /// [异步]根据主键ID获取实体
        /// </summary>
        /// <param name="id">主键ID</param>
        /// <returns></returns>
        public virtual async Task<T> GetByIdAsync(long id)
        {
            return await DbBase.SingleOrDefaultByIdAsync<T>(id);
        }
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <returns></returns>
        public virtual IEnumerable<T> GetAll()
        {
            return DbBase.Query<T>().ToEnumerable();
        }
        /// <summary>
        /// [异步]获取所有数据
        /// </summary>
        /// <returns></returns>
        public virtual async Task<IEnumerable<T>> GetAllAsync()
        {
            return await DbBase.Query<T>().ToEnumerableAsync();
        }
        /// <summary>
        /// 获取NPoco Linq查询对象
        /// </summary>
        /// <returns></returns>
        public virtual IQueryProviderWithIncludes<T> Query()
        {
            return DbBase.Query<T>();
        }
        #endregion
        /// <summary>
        /// 新增数据 
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <remarks>支持两种主键类型：1、自增主键；2、GUID 注：GUID需要给Id赋值</remarks>
        /// <returns></returns>
        public virtual bool Insert(T entity)
        {
            var flag = false;
            try
            {
                if (typeof(TId).Name.ToUpper() == "GUID")
                {
                    var type = DbBase.PocoDataFactory.TableInfoForType(typeof(T));
                    var tbName = type.TableName;
                    var pk = type.PrimaryKey;
                    var result = DbBase.Insert(tbName, pk, false, entity);
                    if (result != null)
                        flag = string.IsNullOrEmpty(result.ToString());
                }
                else
                {
                    var result = DbBase.Insert(entity);
                    if (result != null && !string.IsNullOrEmpty(result.ToString()))
                        flag = Convert.ToInt64(result) > 0;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("新增数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// 添加一条记录
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="type">主键类型</param>
        /// <returns></returns>
        public virtual bool Insert(T entity, KeyType type)
        {
            var flag = false;
            try
            {
                if (type == KeyType.Guid)
                {
                    var tableType = DbBase.PocoDataFactory.TableInfoForType(typeof(T));
                    var tbName = tableType.TableName;
                    var pk = tableType.PrimaryKey;
                    var result = DbBase.Insert(tbName, pk, false, entity);
                    if (result != null)
                        flag = string.IsNullOrEmpty(result.ToString());
                }
                else
                {
                    var result = DbBase.Insert(entity);
                    if (result != null && !string.IsNullOrEmpty(result.ToString()))
                        flag = Convert.ToInt64(result) > 0;
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("新增数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns></returns>
        public virtual bool Update(T entity)
        {
            bool flag;
            try
            {
                var row = DbBase.Update(entity);
                flag = row > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("修改数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;

        }
        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns></returns>
        public virtual bool Delete(T entity)
        {
            bool flag;
            try
            {
                var row = DbBase.Delete(entity);
                flag = row > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("删除数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }

        #region Insert Delete Update
        /// <summary>
        /// [异步]新增数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns></returns>
        public virtual async Task<bool> InsertAsync(T entity)
        {
            var flag = false;
            try
            {
                var result = await DbBase.InsertAsync(entity);
                if (result != null)
                    flag = string.IsNullOrEmpty(result.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("新增数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// [异步][未实现]新增数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <param name="type">主键类型</param>
        /// <returns></returns>
        public virtual Task<bool> InsertAsync(T entity, KeyType type)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 批量新增数据
        /// </summary>
        /// <param name="entitys"></param>
        public virtual void InsertBulk(IEnumerable<T> entitys)
        {
            DbBase.InsertBulk(entitys);
        }
        /// <summary>
        /// 批量新增数据
        /// </summary>
        /// <param name="entitys">对象列表</param>
        /// <param name="type">主键类型</param>
        public virtual void InsertBulk(IEnumerable<T> entitys, KeyType type)
        {
            try
            {
                if (type == KeyType.Guid)
                {
                    var tableType = DbBase.PocoDataFactory.TableInfoForType(typeof(T));
                    var tbName = tableType.TableName;
                    var pk = tableType.PrimaryKey;

                    using (var tran = DbBase.GetTransaction())
                    {
                        foreach (var item in entitys)
                        {
                            DbBase.Insert(tbName, pk, false, item);
                        }
                        tran.Complete();
                    }
                }
                else
                {
                    DbBase.InsertBulk(entitys);
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("批量新增数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
        }
        /// <summary>
        /// [异步]更新数据
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public virtual async Task<bool> UpdateAsync(T entity)
        {
            bool flag;
            try
            {
                var row = await DbBase.UpdateAsync(entity);
                flag = row > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("修改数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// [异步]删除数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <returns></returns>
        public virtual async Task<bool> DeleteAsync(T entity)
        {
            bool flag;
            try
            {
                var row = await DbBase.DeleteAsync(entity);
                flag = row > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("删除数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="primaryKey">主键ID</param>
        /// <returns></returns>
        public virtual bool Delete(TId primaryKey)
        {
            bool flag;
            try
            {
                var row = DbBase.Delete<T>(primaryKey);
                flag = row > 0;
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("删除数据时发生错误,实体类名为,实体类名为:{0},错误信息:{1}", typeof(T).FullName, ex.Message));
            }
            return flag;
        }
        /// <summary>
        /// 获取 NPoco Linq 更新对象
        /// </summary>
        /// <returns></returns>
        public virtual IUpdateQueryProvider<T> UpdateMany()
        {
            return DbBase.UpdateMany<T>();
        }
        /// <summary>
        /// 获取 NPoco Linq 删除对象
        /// </summary>
        /// <returns></returns>
        public virtual IDeleteQueryProvider<T> DeleteMany()
        {
            return DbBase.DeleteMany<T>();
        }
        #endregion

        /// <summary>
        /// 保存数据
        /// </summary>
        /// <param name="entity">实体对象</param>
        /// <remarks>此方法适用于自增主键，根据Id判断是新增还是修改数据</remarks>
        /// <returns></returns>
        public bool Save(T entity)
        {
            try
            {
                DbBase.Save(entity);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
